<?php

/**
 * Array auth adapter
 *
 * @author     Mon Zafra <monzee at gmail>
 * @copyright  (c)2009 Mon Zafra
 * @category   Mz
 * @package
 * @license    http://mz-project.googlecode.com/svn/trunk/LICENSE    MIT License
 * @version    SVN: $Id: Array.php 43 2009-05-18 11:54:11Z monzee $
 */
class Admin_Model_Auth_Array implements Zend_Auth_Adapter_Interface
{
    protected $_username;
    protected $_password;
    protected $_users;
    protected $_userRoles;
    protected $_aclModel;

    /**
     * constructor
     *
     * possible option keys (case-sensitive):
     * - users       array
     * - userRoles   array
     * - aclModel    Admin_Model_Acl_Adapter
     *
     * @param string            $username
     * @param string            password  Should be hashed already
     * @param array|Zend_Config $options  
     */
    public function __construct($username, $password, $options = array())
    {
        $this->_username = $username;
        $this->_password = $password;
        if (!empty($options)) {
            $this->setOptions($options);
        }
    }

    /**
     * Set adapter options.
     *
     * @param array|Zend_Config $options
     * @return Admin_Model_Auth_Array
     * @throws Admin_Mode_Auth_Exception If $options is not an array/Zend_Config
     */
    public function setOptions($options)
    {
        if ($options instanceof Zend_Config) {
            $options = $options->toArray();
        } else if (!is_array($options)) {
            throw new Admin_Model_Auth_Exception('Invalid options passed to acl model adapter');
        }
        foreach ($options as $opt => $val) {
            $setter = 'set' . $opt;
            $this->$setter($val);
        }
        return $this;
    }

    /**
     * Capture set* calls
     *
     * @param string $method
     * @param array  $args
     * @return Admin_Model_Auth_Array
     * @throws BadMethodCallException If the first 3 letters != 'set' (case-
     * sensitive).
     */
    public function __call($method, $args)
    {
        if ('set' == substr($method, 0, 3)) {
            $prop = '_' . strtolower($method[3]) . substr($method, 4);
            if (property_exists($this, $prop)) {
                $this->$prop = $args[0];
            }
        } else {
            throw new BadMethodCallException('No such method (' . $method . ').');
        }
        return $this;
    }

    /**
     *
     * @return Admin_Model_Acl_Adapter
     */
    public function getAclModel()
    {
        if (null === $this->_aclModel) {
            $this->_aclModel = 
                Zend_Controller_Action_HelperBroker::getStaticHelper('AccessManager')
                                                   ->getAclModel()
                                                   ->getAdapter();
        }
        return $this->_aclModel;
    }

    /**
     *
     * @param Admin_Model_Acl_Adapter $model
     * @return Admin_Model_Auth_Array
     */
    public function setAclModel(Admin_Model_Acl_Adapter $model)
    {
        $this->_aclModel = $model;
        return $this;
    }


    /**
     *
     * @return Zend_Auth_Result
     */
    public function authenticate()
    {
        $model = $this->getAclModel();
        // TODO: eh, this isn't really an Array adapter if it doesn't use Array
        //       all the time. rename class or force the Array adapter?
        try {
            $user = $model->getUserByUsername($this->_username);
            if ($user['password'] == $this->_password) {
                return new Zend_Auth_Result(
                    Zend_Auth_Result::SUCCESS,
                    $this->_createIdentity($user),
                    array('Authentication successful.')
                );
            } else {
                return new Zend_Auth_Result(
                    Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID,
                    $this->_username,
                    array('Invalid password.')
                );
            }
        } catch (Admin_Model_Acl_Exception $e) {
            return new Zend_Auth_Result(
                Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND,
                $this->_username,
                array('No such user.')
            );
        }
    }

    protected function _createIdentity($user)
    {
        unset($user['password']);
        $userRoles = $this->getAclModel()->getUserRoles($user);
        $user['roles'] = array();
        foreach ($userRoles as $role) {
            $user['roles'][] = $role['id'];
        }
        return new Admin_Model_Auth_Identity($user);
    }

}